package com.sinodata.bsm.cicp.collector.common;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.util.DBConnectionUtil;
import com.sinodata.bsm.cicp.util.ProtocolParameterUtil;
import com.sinodata.bsm.common.constants.DataTypeConstants;
import com.sinodata.bsm.common.vo.ProtocolParameter;
import com.sinodata.bsm.common.vo.ResPropertyValue;

/**
 * 
 * <p>
 * Description: 数据库连接状态采集器，连接不上认为连接断开，超时1分钟认为连接超时。
 * </p>
 *
 * @author liulibo
 * @version 1.1

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-10-12 PM 1:33:30    liulibo        1.0         To create
 * 2012-10-12 AM 10:51:30   liulibo        1.1         修改机制，无法连接时，响应时间为空值
 * </p>
 *
 * @since 
 * @see
 */
public class DBConnectCollector extends Collector {

    private static Logger logger = Logger.getLogger(DBConnectCollector.class);
    private static final int DEFAULT_TIME_OUT = 60;
    private int status = 2;// 0表示断开，1表示正常连接，2表示连接超时
    private String url = null;
    private String port = null;
    private String usr = null;
    private String pwd = null;
    private String dbtype;
    private String dbname;
    private String sql;
    private String value = DataTypeConstants.DATA_NOT_AVAILABLE;
    private final Object waitLock = new Object();
    private boolean isWait = true;
    private static Properties sqlProperies = null;
    static {
        sqlProperies = new Properties();
        File file = new File("cicp-conf/sqlIdentify.properties");
        try {
            FileInputStream fis = new FileInputStream(file);
            sqlProperies.load(fis);
        } catch (Exception e) {
            logger.error("系统找不到指定的文件", e);
        } finally {

        }
    }

    @Override
    public List<ResPropertyValue> collect(final String ip) {
        dbtype = getParamMap().get("DBType");
        dbname = getParamMap().get("DBName");
        sql = sqlProperies.getProperty(dbtype.toLowerCase());
        ProtocolParameter protocolParameter = ProtocolParameterUtil.getJdbcValue(ip, dbtype, dbname);
        isWait = true;
        status = 2;
        if (protocolParameter != null) {
            url = protocolParameter.getUrl();
            port = protocolParameter.getPort() + "";
            usr = protocolParameter.getUserName();
            pwd = protocolParameter.getPwd();
            url = url.replace("$ip", ip);
            url = url.replace("$dbname", dbname);
            url = url.replace("$port", port);
            url = url.replace("$usr", usr);
            url = url.replace("$pwd", pwd);

            /**
             * 创建一个线程来创建数据库连接， 存在一个问题：如果创建连接不成功，并且超时失效的情况下，该线程将不能退出
             */
            new Thread() {
                @Override
                public void run() {
                    Connection conn = null;
                    Statement statement = null;
                    ResultSet results = null;
                    long startTime = System.currentTimeMillis();
                    try {
                        DriverManager.setLoginTimeout(DEFAULT_TIME_OUT);
                        conn = DriverManager.getConnection(url, usr, pwd);
                        if (sql != null && sql.trim().length() > 0) {
                            statement = conn.createStatement();
                            statement.setQueryTimeout(DEFAULT_TIME_OUT);
                            results = statement.executeQuery(sql);
                            Long time = System.currentTimeMillis() - startTime;
                            value = time.toString();
                        }
                        status = 1;// 连接正常
                    } catch (Exception e) {
                        logger.error("failed to collect db connect stauts,ip=" + ip + ",dbtype=" + dbtype + ",dbname=" + dbname + ",sql=" + (sql == null ? "null" : sql), e);
                        status = 0;// 连接断开
                    } finally {
                        if (results != null) {
                            try {
                                results.close();
                            } catch (SQLException e1) {
                            }
                        }
                        if (statement != null) {
                            try {
                                statement.close();
                            } catch (SQLException e1) {
                            }
                        }
                        if (conn != null) {
                            try {
                                conn.close();
                            } catch (SQLException e1) {
                            }
                        }
                        synchronized (waitLock) {
                            waitLock.notifyAll();
                            isWait = false;
                        }
                    }
                }
            }.start();
            try {
                synchronized (waitLock) {
                    if (isWait) {
                        waitLock.wait(DEFAULT_TIME_OUT * 1000L);
                    }
                }
            } catch (InterruptedException e) {

            }
        } else {
            status = 0;
        }
        List<ResPropertyValue> result = new ArrayList<ResPropertyValue>();
        String[] propMetas = getPropMeta();
        ResPropertyValue propertyValueX = new ResPropertyValue();
        ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
        propValues[0] = ResPropertyValue.createPropValue(status == 1 ? "CONNECTED" : status == 2 ? "TIMEOUT" : "DISCONNECTED", propMetas[0]);
        propValues[1] = ResPropertyValue.createPropValue(value, propMetas[1]);
        propertyValueX.setValues(propValues);
        result.add(propertyValueX);

        /**
         * 通知连接池管理，该数据库连接是否可用
         */
        DBConnectionUtil.getInstance().setConnectionEnable(dbtype, ip, dbname, status == 1);
        return result;
    }

    @Override
    public String[] getParamMeta() {
        return new String[] { "DBType", "DBName" };
    }

    @Override
    public String[] getPropMeta() {
        return new String[] { "ConnStatus", "ResponseTime" };
    }

}
